package com.ios.service.impl;

import com.ios.mapper.ReservationMapper;
import com.ios.mapper.RoomMapper;
import com.ios.model.entity.Reservation;
import com.ios.model.entity.Room;
import com.ios.model.enums.ReservationStatus;
import com.ios.model.enums.TimeSlot;
import com.ios.service.ReservationService;
import com.ios.service.ViolationService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;

import static org.apache.commons.lang3.time.DateUtils.isSameDay;

/**
 * 预约记录服务实现
 */
@Service
public class ReservationServiceImpl implements ReservationService {
    @Autowired
    private ReservationMapper reservationMapper;

    @Autowired
    private ViolationService violationService;
    @Autowired
    private RoomMapper roomMapper;
    @Autowired
    private SysUserMapper userMapper;
    /**
     * 增强版 - 获取预约详情（实时计算状态）
     */
    @Override
    public Reservation selectReservationById(Long id) {
        Reservation reservation = reservationMapper.selectReservationById(id);
        calculateRealTimeStatus(reservation); // 实时计算状态（修改原对象，不返回）
        return reservation;
    }

    /**
     * 增强版 - 查询预约列表（实时计算状态）
     */
    @Override
    public List<Reservation> selectReservationList(Reservation query) {
        // 开启分页（已经在 Controller 中调用 startPage()，这里不用重复）

        // 拿到分页结果（注意 Page 类型）
        List<Reservation> rawList = reservationMapper.selectReservationList(query);

        // 在原列表上更新状态（不要替换为新列表）
        for (Reservation reservation : rawList) {
            calculateRealTimeStatus(reservation); // 不返回值，直接改原对象
        }

        // 返回原列表，PageHelper 可以正确处理分页
        return rawList;
    }


    /**
     * 实时计算预约状态（核心方法）
     */
    private void calculateRealTimeStatus(Reservation reservation) {
        if (reservation == null ||
                reservation.getStatus() != ReservationStatus.PENDING_CHECK_IN.getCode()) {
            return;
        }

        LocalDate reserveDate = reservation.getReservationDate().toInstant()
                .atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate today = LocalDate.now();

        if (reserveDate.isBefore(today)) {
            reservation.setStatus(ReservationStatus.NOT_CHECKED_IN.getCode());
            reservationMapper.updateReservation(reservation);
            return;
        }

        if (reserveDate.isEqual(today)) {
            LocalTime now = LocalTime.now();
            boolean isExpired = switch (reservation.getTimeSlot()) {
                case 1 -> now.isAfter(LocalTime.of(12, 0));
                case 2 -> now.isAfter(LocalTime.of(14, 0));
                case 3 -> now.isAfter(LocalTime.of(22, 0));
                default -> false;
            };

            if (isExpired) {
                reservation.setStatus(ReservationStatus.NOT_CHECKED_IN.getCode());
                reservationMapper.updateReservation(reservation);
            }
        }
    }


    /**
     * 补偿性定时任务（处理漏网之鱼）
     */
    @Scheduled(cron = "0 0 9 * * ?") // 每天上午9点执行（覆盖所有前一天的可能漏检）
    @Transactional
    public void compensateExpiredReservations() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        List<Reservation> expired = reservationMapper.selectByStatusAndDate(
                ReservationStatus.PENDING_CHECK_IN.getCode(),
                Date.from(yesterday.atStartOfDay(ZoneId.systemDefault()).toInstant())
        );

        expired.forEach(res -> {
            res.setStatus(ReservationStatus.NOT_CHECKED_IN.getCode());
            reservationMapper.updateReservation(res);
        });
    }


    @Override
    @Transactional
    public int insertReservation(Reservation reservation) {
        TimeSlot timeSlot = TimeSlot.fromCode(reservation.getTimeSlot());
        LocalDate reservationDate = reservation.getReservationDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        LocalTime startTime;
        switch(timeSlot.getCode()) {
            case 1: startTime = LocalTime.of(8, 0); break;
            case 2: startTime = LocalTime.of(12, 0); break;
            case 3: startTime = LocalTime.of(18, 0); break;
            default: throw new IllegalArgumentException("无效的时间段");
        }

        LocalDateTime reservationDateTime = LocalDateTime.of(reservationDate, startTime);
        // 校验预约日期是否为未来
        if (reservationDateTime.isBefore(LocalDateTime.now())) {
            throw new RuntimeException("只能预约未来时间");
        }

        // 检查时间段冲突
        if (hasTimeSlotConflict(reservation)) {
            throw new RuntimeException("该时间段已被预约");
        }
        Room room=roomMapper.selectRoomById(reservation.getRoomId());
        SysUser user = userMapper.selectUserById(reservation.getUserId());
        if (user.getCredit()<60){//信誉分小于60
            throw new RuntimeException("信誉分不足60,不能预约");
        }
        if (room.getIsPaid()==1){//是收费的
            if(user.getBalance().compareTo(room.getPrice())<0){
                throw new RuntimeException("余额不足，请先充值");
            }
        }
        BigDecimal remaining = user.getBalance().subtract(room.getPrice());
        user.setBalance(remaining);
        userMapper.updateUser(user);
        // 设置初始状态
        reservation.setStatus(ReservationStatus.PENDING_REVIEW.getCode());
        reservation.setApplyTime(new Date());
        return reservationMapper.insertReservation(reservation);
    }

    @Override
    public int updateReservation(Reservation reservation) {
        return reservationMapper.updateReservation(reservation);
    }

    @Override
    public int deleteReservationById(Long id) {
        return reservationMapper.deleteReservationById(id);
    }

    @Override
    public int deleteReservationByIds(Long[] ids) {
        return reservationMapper.deleteReservationByIds(ids);
    }

    @Override
    @Transactional
    public int cancelReservation(Long id, Long userId, String reason) {
        Reservation reservation = reservationMapper.selectReservationById(id);

        // 校验
        if (reservation == null) {
            throw new RuntimeException("预约记录不存在");
        }
        if (!reservation.getUserId().equals(userId)) {
            throw new RuntimeException("只能取消自己的预约");
        }
        if (reservation.getStatus() != ReservationStatus.PENDING_REVIEW.getCode()) {
            throw new RuntimeException("当前状态不可取消");
        }

        // 更新
        reservation.setStatus(ReservationStatus.CANCELLED.getCode());
        reservation.setReason(reason);
        return reservationMapper.updateReservation(reservation);
    }

    @Override
    @Transactional
    public int reviewReservation(Long id, Long reviewerId, boolean approved, String reason) {
        Reservation reservation = reservationMapper.selectReservationById(id);

        // 校验
        if (reservation == null) {
            throw new RuntimeException("预约记录不存在");
        }
        if (reservation.getStatus() != ReservationStatus.PENDING_REVIEW.getCode()) {
            throw new RuntimeException("只能审核待审核的预约");
        }

        // 更新
        if (approved) {
            reservation.setStatus(ReservationStatus.PENDING_CHECK_IN.getCode());
            reservation.setReason(reason);
        } else {
            reservation.setStatus(ReservationStatus.REJECTED.getCode());
            reservation.setReason(reason);
        }
        reservation.setReviewerId(reviewerId);
        reservation.setReviewTime(new Date());
        return reservationMapper.updateReservation(reservation);
    }

    @Override
    @Transactional
    public int checkIn(Long id, Long userId) {
        Reservation reservation = reservationMapper.selectReservationById(id);

        // 校验
        if (reservation == null) {
            throw new RuntimeException("预约记录不存在");
        }
        if (!reservation.getUserId().equals(userId)) {
            throw new RuntimeException("只能签到自己预约的记录");
        }
        if (reservation.getStatus() != ReservationStatus.PENDING_CHECK_IN.getCode()) {
            throw new RuntimeException("当前状态不可签到");
        }
        if (!isSameDay(reservation.getReservationDate(), new Date())) {
            System.out.println(reservation.getReservationDate());
            System.out.println(new Date());
            throw new RuntimeException("只能在预约当天签到");
        }
        // 更新
        SysUser user = userMapper.selectUserById(userId);
        Long credit = user.getCredit();
        credit=Math.min(credit+3,100);
        user.setCredit(credit);
        userMapper.updateUser(user);
        reservation.setStatus(ReservationStatus.CHECKED_IN.getCode());
        reservation.setCheckInTime(new Date());
        return reservationMapper.updateReservation(reservation);
    }

    @Override
    public boolean hasTimeSlotConflict(Reservation reservation) {
        int count = reservationMapper.checkTimeSlotConflict(
                reservation.getSeatId(),
                reservation.getReservationDate(),
                reservation.getTimeSlot(),
                reservation.getId() == null ? 0 : reservation.getId(),
                reservation.getUserId()
        );
        return count > 0;
    }
    @Override
    public List<Reservation> selectReservationsByUserId(Long userId) {
        List<Reservation> list = reservationMapper.selectReservationsByUserId(userId);

        // 在原始 list 上处理状态（不要替换）
        for (Reservation reservation : list) {
            calculateRealTimeStatus(reservation); // 直接修改 reservation 本身
        }

        return list;
    }


}